In [ ]:
import json
import plotly.graph_objects as go
import numpy as np
from scipy.optimize import curve_fit
from scipy.integrate import quad
处理三组数据,存为json格式方便调用及储存
In [2]:
def save(file_path,save_path):
# 初始化两个空列表来存储时间和电压
time = []
voltage = []
# 打开并读取文件
with open(file_path, 'r') as file:
for line in file:
# 移除行末的换行符并分割数据
parts = line.strip().split('\t') # 按制表符分割
if len(parts) == 2:
# 将时间和电压添加到对应的列表
time.append(float(parts[0])) # 时间
voltage.append(float(parts[1])) # 电压
# 创建字典并存储时间和电压数据
dic = {}
dic["time"] = time
dic["voltage"] = voltage
# 将数据写入 JSON 文件
with open(save_path, "w", encoding="utf-8") as file2:
json.dump(dic, file2, indent=4, ensure_ascii=False) # 保证中文字符能正确写入
print(f"数据已成功保存到 {save_path}")#"物块质量.txt"
#"液氮数据.txt"
save(r"定标.txt","dingbiao.json")
save(r"物块质量.txt","wukuai.json")
save(r"液氮数据.txt","yedan.json")
数据已成功保存到 dingbiao.json 数据已成功保存到 wukuai.json 数据已成功保存到 yedan.json
导入储存的在.json数据
In [3]:
with open("dingbiao.json","r",encoding= "UTF-8") as file:
dingbiaodata = json.load(file)
with open("wukuai.json","r",encoding= "UTF-8") as file:
wukuaidata = json.load(file)
with open("yedan.json","r",encoding= "UTF-8") as file:
yedandata = json.load(file)
绘制三幅散点图方便查找数据
In [4]:
def pic(data,title,begin):
# 从 JSON 中提取时间和电压数据
time = data["time"][begin:]
voltage = data["voltage"][begin:]
# 创建一个散点图
fig = go.Figure()
# 添加散点数据
fig.add_trace(go.Scatter(
x=time,
y=voltage,
mode='markers', # 'markers' 表示散点
marker=dict(size=6, color='blue'),
text=[f'时间: {t:.4f}秒<br>电压: {v:.8f}伏特' for t, v in zip(time, voltage)], # 提供悬停时显示的信息
hoverinfo='text' # 显示文本信息
))
# 设置图表的标题和标签
fig.update_layout(
title= title,
xaxis_title='时间 (s)',
yaxis_title='电压 (V)',
template='plotly',
)
# 显示图表
fig.show()
pic(dingbiaodata,"砝码定标散点数据",0)
pic(wukuaidata,"物块质量散点数据",0)
pic(yedandata,"液氮散点数据",0)
发现最后一个图放入泡沫桶前后的数据变化太大,由图选取30s后的数据作为初始记录点,重新绘制下图
In [5]:
pic(yedandata,"液氮散点数据",270) #177,223|248,331|402,471|540,641
In [6]:
dingbiao_begin_time = [2,40,75,146,110,185,234,272,320]
考虑到采样频率为9hz,下标数 dingbiao_begin_index[n] =9 * dingbiao_begin_time[n]
In [7]:
dingbiao_begin_index = []
for n in range(0,len(dingbiao_begin_time)):
dingbiao_begin_index.append(9 * dingbiao_begin_time[n])
print(dingbiao_begin_index)
[18, 360, 675, 1314, 990, 1665, 2106, 2448, 2880]
定义求一段时间内电压平均值函数
In [8]:
def averV(beginlist,data):
avedata = []
sumV = 0
for a in beginlist:
sumV = 0
for v in data["voltage"][a:a+23 * 9]:
sumV += v
avrV = float(sumV) / (23 * 9)
avedata.append(avrV)
return avedata
dingbiao_ave = averV(dingbiao_begin_index,dingbiaodata)
for i in dingbiao_ave:
print(i,"\t")
0.00014051120772946857 0.00016345531400966168 0.0001863969082125605 0.00020942574879227047 0.00023230082125603866 0.0002553376811594205 0.00027830739130434775 0.0003012528502415458 0.0003241877777777775
有了这些数据我们就可以对电压和质量进行定标做出V-M图
In [9]:
# 示例数据
X = []
for n in range(0, 9):
X.append(25 * n)
x = np.array(X)
y = np.array(dingbiao_ave)
# 已知的截距
intercept = 0.00014051120772946857
# 定义线性函数(固定截距,只拟合斜率)
def linear_function(x, slope):
return slope * x + intercept # 截距是固定的,斜率是拟合参数
# 使用 curve_fit 函数拟合数据,固定截距
params, covariance = curve_fit(linear_function, x, y, p0=[1]) # p0 = [1] 为斜率的初始值
slope_fitted = params[0] # 拟合出的斜率
# 计算拟合直线的 y 值
y_fitted = linear_function(x, slope_fitted)
# 扩展 x 的范围,从 0 延伸到比最大值大的地方
x_extended = np.linspace(0, max(x) * 1.5, 100) # 从 0 到 x 最大值的 1.5 倍,生成 100 个点
y_extended = linear_function(x_extended, slope_fitted) # 计算扩展的 x 对应的 y 值
# 创建散点图和拟合直线的 Plotly 图形
fig = go.Figure()
# 添加散点数据
fig.add_trace(go.Scatter(
x=x,
y=y,
mode='markers',
name='数据点',
marker=dict(size=8, color='blue')
))
# 添加拟合直线(包括延长部分)
fig.add_trace(go.Scatter(
x=x_extended,
y=y_extended,
mode='lines',
name='拟合直线',
line=dict(color='red', width=2)
))
# 在图中添加斜率和截距的文本注释
slope_text = f"斜率: {slope_fitted:.8f}"
intercept_text = f"截距: {intercept:.8f}"
# 设置图表标题和坐标轴标签
fig.update_layout(
title='散点图与线性拟合直线(固定截距)',
xaxis_title='质量(g)',
yaxis_title='电压 (V)',
template='plotly',
showlegend=True,
annotations=[
# 在图表上添加斜率的注释
go.layout.Annotation(
x=0.5, # x 坐标位置
y=0.9, # y 坐标位置
xref="paper",
yref="paper",
text=slope_text, # 斜率文本
showarrow=False, # 不显示箭头
font=dict(size=12, color="black"), # 字体大小和颜色
align="center"
),
# 在图表上添加截距的注释
go.layout.Annotation(
x=0.5,
y=0.85,
xref="paper",
yref="paper",
text=intercept_text, # 截距文本
showarrow=False,
font=dict(size=12, color="black"),
align="center"
),
]
)
# 显示图表
fig.show()
# 打印拟合的斜率
print(f"拟合的斜率: {slope_fitted:.8f}")
print(f"已知的截距: {intercept:.8f}")
拟合的斜率: 0.00000092 已知的截距: 0.00014051
由此得到的质量和电压的关系为 $U = 0.00000092 m + 0.00014051$
根据定标直线求投入四个物块的质量¶
(小铜块,大铜块,不锈钢块,铝块)
求出各个物块电压平均值,先求出开始下标,取之后23s内的所有点
In [10]:
wukuai_begin_time = [8,43,83,102]
wukuai_begin_index = [72,387,747,918]
求出电压平均值(用到之前定义的aveV函数)
In [11]:
ave_wukuai = averV(wukuai_begin_index,wukuaidata)
print(ave_wukuai)
[0.00015928115942028998, 0.00019470700483091777, 0.00015566652173913025, 0.0001506016908212561]
用定标直线求出对应质量(单位g)顺序:小铜块,大铜块,钢块,铝块
In [12]:
def m(index):
m = (index - 0.00014051) / 0.00000092
return m
wukuai_m = [m(ave_wukuai[0]),m(ave_wukuai[1]),m(ave_wukuai[2]),m(ave_wukuai[3])]
print(wukuai_m)
[20.403434152489115, 58.90978785969324, 16.474480151228537, 10.969229153539237]
对液氮数据进行处理,求出前后液氮质量的变化¶
先标出变化的起始结束时间点
In [13]:
yedanbegin = [177,248,402,540]#177,223|248,331|402,471|540,641
yedanend = [223,331,471,641]
def liner(begin,end,data):
x = data["time"][begin * 9:end * 9]
y = data["voltage"][begin * 9:end * 9]
slope, intercept = np.polyfit(x, y, 1)
return slope, intercept
求出五条U - T直线的斜率和截距,并保存 由前文,U = 0.00000092 m + 0.00014051
In [14]:
def U(m):
return 0.00000092 * m + 0.00014051
def M(u):
return (u - 0.00014051)/ 0.00000092
slopes = []
intercepts = []
for begintime in yedanbegin:
slopei,intercepti = liner(begintime - 23,begintime,yedandata)
slopes.append(slopei)
intercepts.append(intercepti)
slopei,intercepti = liner(641,641 + 23,yedandata)
slopes.append(slopei)
intercepts.append(intercepti)
print(slopes,intercepts)
[np.float64(-1.8857526051511306e-08), np.float64(-1.872820462795376e-08), np.float64(-1.772900087015145e-08), np.float64(-1.9201379398350535e-08), np.float64(-1.5404261163151113e-08)] [np.float64(0.0003516805009405124), np.float64(0.0003527357644797613), np.float64(0.00036075847008853806), np.float64(0.0003730404371479554), np.float64(0.0004054118255828527)]
求出四次投入的中间时刻,并对其液氮蒸发量进行计算
In [15]:
Midtime = []
yedanM= []
for i in range(0,4):
Midtime.append((yedanend[i] + yedanbegin[i])/2)
print("Midtime",Midtime)
shunxu =[3,2,0,1]
for n in range(0,4):
U1 = intercepts[n+1] + slopes[n+1] * Midtime[n]
U2 = intercepts[n] + slopes[n] * Midtime[n]
changeU = intercepts[n+1] - intercepts[n] + Midtime[n] * (slopes[n + 1] - slopes[n])
yedanM.append(M(U2) - M(U1) + wukuai_m[shunxu[n]]) #wukuai_m 顺序为小铜,大铜,钢,铝
print(M(U1),M(U2),M(changeU))
print(yedanM)
Midtime [200.0, 289.5, 436.5, 590.5] 226.6088299501854 225.433691011098 -151.55312193047783 233.82165688764044 224.78690134779202 -143.6935053297168 243.6402554788863 230.98887087904015 -140.07687626971907 278.0495753978391 240.42611153611895 -115.10479700784508 [np.float64(9.794090214451847), np.float64(7.439724611380118), np.float64(7.752049552642962), np.float64(21.286323997973113)]
由此获得了所有的数据,绘制出最终图片
In [16]:
def pic2(data, title, begin, slopes, intercepts):
# 从 JSON 中提取时间和电压数据
time = data["time"][begin:]
voltage = data["voltage"][begin:]
# 创建一个散点图
fig = go.Figure()
line_styles = ['solid', 'dash', 'dot', 'longdash', 'dashdot']
# 添加散点数据
fig.add_trace(go.Scatter(
x=time,
y=voltage,
mode='markers', # 'markers' 表示散点
marker=dict(size=6, color='blue'),
text=[f'时间: {t:.4f}秒<br>电压: {v:.8f}伏特' for t, v in zip(time, voltage)], # 提供悬停时显示的信息
hoverinfo='text' # 显示文本信息
))
i = 0
# 添加五条直线
for slope, intercept in zip(slopes, intercepts):
# 计算直线的x轴范围
x_range = np.linspace(min(time), max(time), 100)
# 计算y轴上的对应点
y_range = slope * x_range + intercept
# 添加直线到图中
fig.add_trace(go.Scatter(
x=x_range,
y=y_range,
mode='lines', # 'lines' 表示线条
line=dict(color='red', width=2, dash=line_styles[i]),
name=f'直线: y={slope:.10f}x + {intercept:.8f}' # 直线方程
))
i += 1
# 设置图表的标题和标签
fig.update_layout(
title=title,
xaxis_title='时间 (s)',
yaxis_title='电压 (V)',
template='plotly',
)
# 显示图表
fig.show()
pic2(yedandata,"液氮拟合直线和散点图",270,slopes,intercepts)
Cu的定压比热容Cp与温度T的关系拟合图
In [ ]:
# 样条插值
spline = CubicSpline(x_data, y_data)
# 创建拟合曲线数据
x_fit = np.linspace(min(x_data), max(x_data), 500)
y_fit = spline(x_fit)
# 绘制拟合曲线
plt.plot(x_data, y_data, 'bo', label="Data")
plt.plot(x_fit, y_fit, 'r-', label="Cubic Spline")
plt.xlabel("X")
plt.ylabel("Y")
plt.legend()
plt.show()
# 对样条插值曲线从 x=78 到 x=293 进行积分
integral, error = quad(spline, 78, 293)
print(f"从 78 到 293 的积分值: {integral}")
从 78 到 293 的积分值: 71111.57134382188
In [11]:
# 定义被积函数
def integrand(x):
return x**3 / (np.exp(x) - 1)
# 积分范围 [0, 343/293]
lower_limit = 0
upper_limit = 343 / 78
# 使用quad进行数值积分
integral, error = quad(integrand, lower_limit, upper_limit)
# 输出积分结果
print(f"积分结果: {integral}")
积分结果: 4.325307030065073
In [12]:
print(9 * 6.02 *1.38 * 78**4 *4.325307030065073/(343**3))
296.64093328541276
In [15]:
print(58.91/63.546*(4.910-0.2966))
4.276829289018979
In [16]:
print(4.276829289018979/21.28 * 1000)
200.97881997269636